// Bachelor of Software Engineering 
// Media Design School 
// Auckland
// New Zealand
// 
// (c) 2005 - 2014 Media Design School 
// 
// File Name : Stock.cpp
// Description : Stock implementation
// Author : Serge Radinovich
// Mail : srad015@hotmail.com


#include "Stock.h"
#include <assert.h>
#include "Game.h"



////////////////////////////
//Constructor
///////////////////////////
Stock::Stock(std::list<Card*>* _pCards24) 
{
	//Set null spaces
	m_NullSpaces.push_back(GameObject(static_cast<float>(s_kiLeft), static_cast<float>(s_kiTop), Card::s_kiWidth, Card::s_kiHeight));
	m_NullSpaces.push_back(GameObject(static_cast<float>(kiFreeLeft), static_cast<float>(s_kiTop), Card::s_kiWidth, Card::s_kiHeight));
	
	
	//Add a pile for shuffling
	m_Stacks.push_back(new std::list<Card*>);
	//Add a pile to be picked 
	m_Stacks.push_back(new std::list<Card*>);

	auto cardIter = _pCards24->begin();
	for(int i = 0; i < 24; i++)
	{
		m_Stacks[0]->push_back(new Card(*(*cardIter)));
		//Todo set positions
		m_Stacks[0]->back()->SetPos(s_kiLeft, s_kiTop);
		//Remove from list taken from
		delete *cardIter;
		cardIter = _pCards24->erase(cardIter);	
	}

}

////////////////////////////
//Destructor
///////////////////////////
Stock::~Stock(void)
{
	while(!m_StockMoves.empty())
	{
		delete m_StockMoves.top();
		m_StockMoves.pop();
	}
}

////////////////////////////
//Renders top face down card in stock and 3 cards on top of waste
///////////////////////////
void Stock::Draw()
{
	
	//Draw deck
	if(!m_Stacks[0]->empty())
	{
		m_Stacks[0]->front()->Draw();
	}
	else
	{
		//Stock is empty so draw nullspace
		Game* _pGame = Game::GetGameInstance();
		BitBlt(_pGame->GetBackBuffer()->getDC(), s_kiLeft, s_kiTop, Card::s_kiWidth, Card::s_kiHeight, m_hNullSpaceDC, 0, 0, SRCAND);
		
	}

	//Draw waste
	if(!m_Stacks[1]->empty())
	{
		int _iWasteCount = m_Stacks[1]->size() < 3 ? m_Stacks[1]->size() : 3;
		auto _wasteIter = m_Stacks[1]->end();

		//Take iterator back to correct position
		for(int i = 0; i < _iWasteCount; i++)
		{
			_wasteIter--;	 
		}
		//Draw from front to back
		while(_wasteIter != m_Stacks[1]->end())
		{
			(*_wasteIter)->Draw();
			_wasteIter++;
		}
	}
	else
	{
		//Waste is empty so draw null spaces
		Game* _pGame = Game::GetGameInstance();
		BitBlt(_pGame->GetBackBuffer()->getDC(), kiFreeLeft, s_kiTop, Card::s_kiWidth, Card::s_kiHeight, m_hNullSpaceDC, 0, 0, SRCAND);
	}
}

////////////////////////////
//Attempt to grab cards from the waste
//This will either be a click on the stock which takes cards out of the deck to the waste (or back into the stock from waste)
//Or it will allow user to grab 1 card from the waste
///////////////////////////
std::list<Card*>* Stock::AttemptCardGrab(Vector2 _clickPos, std::list<Card*>* grabbedCards)
{
	//Check deck
	if(CheckCollision(_clickPos, &m_NullSpaces[0]))
	{
		//Stock is empty so fill it up with cards from the waste
		if(m_Stacks[0]->empty())
		{
			RepopulateStock();
		}
		else
		{
			//Stock is not empty so put 3 cards maximum into the waste
			int _iTransferredCardCount = m_Stacks[0]->size() < 3 ? m_Stacks[0]->size() : 3;
			StockToWaste(_iTransferredCardCount);
		}
		ArrangeCardPositions();
		return nullptr;
		
	}
	//Click is on Waste
	else if(!m_Stacks[1]->empty())
	{
		if(CheckCollision(_clickPos, m_Stacks[1]->back()))
		{
			grabbedCards->push_front(m_Stacks[1]->back());
			m_Stacks[1]->pop_back();		

			return m_Stacks[1];
		}
		else
		{
			return nullptr;
		}
	}

	
	return nullptr;
}


////////////////////////////
//Set positions of cards depending on which pile they are in
///////////////////////////
void Stock::ArrangeCardPositions()
{
	if(!m_Stacks[1]->empty())
	{
		//Set every card not face up to nullspace coords
		auto _wasteIter = m_Stacks[1]->begin();
		int _iYMult = 0;
		while(_wasteIter != m_Stacks[1]->end())
		{
			//Position waste cards going down the screen if face up
			if(!(*_wasteIter)->IsFaceUp())
			{
				(*_wasteIter)->SetPos(kiFreeLeft, s_kiTop);
			}
			else
			{
				(*_wasteIter)->SetPos(kiFreeLeft, s_kiTop + _iYMult*kiDistBetweenCards);
				_iYMult++;
			}
			_wasteIter++;
		}
		

	}

	//Stock - same position for all
	if(!m_Stacks[0]->empty())
	{
		auto deckCard = m_Stacks[0]->begin();
		while(deckCard != m_Stacks[0]->end())
		{
			(*deckCard)->SetPos(s_kiLeft, s_kiTop);
			deckCard++;
		}
	}
}

////////////////////////////
//Not used for Stock. Inherited from CardPileGroup
///////////////////////////
bool Stock::AttemptCardDeposit(Vector2 _clickPos, std::list<Card*>* _pGrabbedCards,  std::list<Card*>* &_pListDepositedTo)
{
	return false;
}

////////////////////////////
//Called when a card is taken out of waste by player
//Keeps pushing facedown cards up if there are any in the waste
///////////////////////////
void Stock::ResupplyWaste()
{

	//Error check, no need to do anything here
	int _iFaceUpCards = 0;
	auto _wasteIter = m_Stacks[1]->begin();
	while(_wasteIter != m_Stacks[1]->end())
	{
		if((*_wasteIter)->IsFaceUp())
		{
			_iFaceUpCards++;
		}
		_wasteIter++;
	}
	//Error check ends here. Dont push more cards if 3 already face up
	if(_iFaceUpCards == 3)
	{
		return;
	}


	//If there is a card behind top remaining cards, push back 
	if(m_Stacks[1]->size() >= 3)
	{
		_wasteIter = m_Stacks[1]->end();
		_wasteIter--;
		while((*_wasteIter)->IsFaceUp())
		{
			_wasteIter--;
		}
		(*_wasteIter)->Flip();
		ArrangeCardPositions();
	}
}

////////////////////////////
//Undo a move made in relation to the stock
//This is only called in relation to player taking cards out of waste (not clicking on stock)
///////////////////////////
void Stock::UndoMove(Move* _move)
{
	//Flip the third card that is face up on the waste
	if(m_Stacks[1]->size() > 2)
	{
		auto _wasteIter = m_Stacks[1]->end();
		for(int i = 0; i < 3; i++)
		{
			_wasteIter--;
		}
		(*_wasteIter)->Flip();
	}
	
	//Return the single card to the top of waste
	m_Stacks[1]->push_back(_move->m_pCardsMoved->front());

	return;
}

////////////////////////////
//Returns true if mouseclick collides with stock
///////////////////////////
bool Stock::DeckClicked(Vector2 _mouseClick)
{
	if(CheckCollision(_mouseClick, &m_NullSpaces[0]))
	{
		return true;
	}
	else
	{
		return false;
	}
}

////////////////////////////
//Undoes a player move that involved clicking on the stock (not waste)
///////////////////////////
void Stock::UndoDeckClick()
{
	StockMove* _move = m_StockMoves.top();

	//Waste was empty when move was made but stock was not
	if(!_move->m_bStockEmpty)
	{
		//Stock not empty, waste empty
		if(_move->m_bWasteEmpty)
		{		
			while(!_move->m_pCardsMoved->empty())
			{
				_move->m_pCardsMoved->back()->Flip();
				_move->m_pPileMovedFrom->push_back(_move->m_pCardsMoved->back());
				_move->m_pCardsMoved->pop_back();
				_move->m_pPileMovedTo->pop_back();
			
			}
			ArrangeCardPositions();
			if(!m_StockMoves.empty())
			{
				delete m_StockMoves.top();
				m_StockMoves.pop();
			}

			return;
		}
		else 
			//Stock not empty, waste not empty
		{
			//Move cards back to stock
			while(!_move->m_pCardsMoved->empty())
			{
				_move->m_pCardsMoved->back()->Flip();
				_move->m_pPileMovedFrom->push_back(_move->m_pCardsMoved->back());
				_move->m_pCardsMoved->pop_back();
				_move->m_pPileMovedTo->pop_back();
			
			}
			//Flip the required number of cards
			int _iMaxFlips = _move->m_iCardCount <= static_cast<int>(m_Stacks[1]->size()) ? _move->m_iCardCount : static_cast<int>(m_Stacks[1]->size());
			auto _wasteIter = m_Stacks[1]->end();
			_wasteIter--;
			while(_iMaxFlips != 0)
			{		
				if(!(*_wasteIter)->IsFaceUp())
				{
					(*_wasteIter)->Flip();
					_iMaxFlips--;
				}

				if(_wasteIter != m_Stacks[1]->begin())
				{
					_wasteIter--;
				}
				else
				{
					break;
				}
			}
			ArrangeCardPositions();
			if(!m_StockMoves.empty())
			{
				delete m_StockMoves.top();
				m_StockMoves.pop();
			}
			return;
		}
	}
	else
		//Stock was empty! Undo RepopulateStock()
	{
		while(!m_Stacks[0]->empty())
		{
			m_Stacks[1]->push_front(m_Stacks[0]->front());
			m_Stacks[0]->pop_front();	
		}
		auto _wasteIter = m_Stacks[1]->end();
		_wasteIter--;
		for(int i = 0; i < _move->m_iCardCount; i++)
		{
			(*_wasteIter)->Flip();
			_wasteIter--;
		}

		ArrangeCardPositions();
		if(!m_StockMoves.empty())
		{
			delete m_StockMoves.top();
			m_StockMoves.pop();
		}
		return;
	}





}

////////////////////////////
//Move cards from stock to waste when player clicks on stock
///////////////////////////
void Stock::StockToWaste( const int _kiCardCount)
{
	//3 cards (normal swap)
	//2 cards (Stock has run out of cards)	
	//1 card (Player took a card from waste, no swap)

	
	//Record move
	//Make list of cards moved
	std::list<Card*> _MovedCardList;
	bool _bStockEmpty = m_Stacks[0]->empty();
	bool _bWasteEmpty = m_Stacks[1]->empty();
	

	////First flip previous cards on top of waste
	if(!m_Stacks[1]->empty())
	{
		auto _wasteIter = m_Stacks[1]->begin();
		while(_wasteIter != m_Stacks[1]->end())
		{
			if((*_wasteIter)->IsFaceUp())
			{
				(*_wasteIter)->Flip();
			}
			_wasteIter++;
		}
	}
	
	
	//Push cards to waste
	for(int i = 0; i < _kiCardCount; i++)
	{
		
		
		//Add cards to waste
		m_Stacks[1]->push_back(m_Stacks[0]->back());
		m_Stacks[0]->pop_back();
		if(!m_Stacks[1]->back()->IsFaceUp())
		{
			m_Stacks[1]->back()->Flip();
		}
		//Add cards moved to waste to list recording move made //RECORDING MOVE
		_MovedCardList.push_back(m_Stacks[1]->back());
		
	}
	//Add move to stack of StockMoves//FOR RECORDING MOVE
	m_StockMoves.push(new StockMove(_bStockEmpty, _bWasteEmpty, m_Stacks[1], &_MovedCardList, _kiCardCount, m_Stacks[0], this));
}


////////////////////////////
//Put cards from waste into stock when player clicks on an empty stock
///////////////////////////
void Stock::RepopulateStock()
{
	
	//RECORD MOVE
	bool _bStockEmpty = m_Stacks[0]->empty();
	bool _bWasteEmpty = m_Stacks[1]->empty();

	//Grab number of cards to flip during undo
	int _iFlipCount = 0;
	for(auto _wasteIter = m_Stacks[1]->begin(); _wasteIter != m_Stacks[1]->end(); _wasteIter++)
	{
		if((*_wasteIter)->IsFaceUp())
		{
			_iFlipCount++;
		}
	}
	//Add move to stack
	m_StockMoves.push(new StockMove(_bStockEmpty, _bWasteEmpty, nullptr, nullptr, _iFlipCount, nullptr, this));

	//Flip required cards
	if(m_Stacks[0]->empty())
	{
		while(!m_Stacks[1]->empty())
		{
			m_Stacks[0]->push_front(m_Stacks[1]->front());
			m_Stacks[1]->pop_front();
			if(m_Stacks[0]->front()->IsFaceUp())
			{
				m_Stacks[0]->front()->Flip();
			}
			
		}
	}
	else
	{
		//Stock is not empty so continue game
		return;
	}
}